import {Matrix4, Quaternion} from "three";

class PosLookCamera {
    constructor(object3D, camera, target) {
        const box = new THREE.Box3()

        const targetPosition = new THREE.Vector3()
        const targetQuaternion = new THREE.Quaternion()
        const q1 = new THREE.Quaternion()
        const q2 = new THREE.Quaternion()

        const _temp = new THREE.Vector3()

        const editorCamera = camera
        const _object3D = new THREE.Object3D()

        this.isRotate = false

        this.onComplete = null

        object3D.updateMatrixWorld()
        box.setFromObject(object3D)
        let boxSize = box.getSize(_temp.clone())
        let focusPoint = box.getCenter(_temp.clone())
        let radius = boxSize.clone().sub(focusPoint).length() * 3 / 2

        this.getCenter = () => {
            return box.getCenter(_temp.clone())
        }

        this.getLength = () => {
            boxSize = box.getSize(_temp.clone())
            focusPoint = box.getCenter(_temp.clone())
            return boxSize.clone().sub(focusPoint).length()
        }

        this.setDirection = (name) => {
            boxSize = box.getSize(_temp.clone())
            focusPoint = box.getCenter(_temp.clone())
            radius = boxSize.clone().sub(focusPoint).length() * 3 / 2
            target.copy(focusPoint)

            switch (name) {
                case 'left':
                    targetPosition.set(1, 0, 0)
                    targetQuaternion.setFromEuler(new THREE.Euler(0, Math.PI * 0.5, 0))
                    break

                case 'before':
                    targetPosition.set(0, 0, 1)
                    targetQuaternion.setFromEuler(new THREE.Euler())
                    break

                case 'side':
                    targetPosition.set(1, 0, 1)
                    targetQuaternion.setFromEuler(new THREE.Euler(0, -Math.PI * 0.5, 0))
                    break
            }

            targetPosition.multiplyScalar(radius).add(focusPoint)

            _object3D.position.copy(focusPoint)

            _object3D.lookAt(editorCamera.position)
            q1.copy(_object3D.quaternion)

            _object3D.lookAt(targetPosition)
            q2.copy(_object3D.quaternion)

            this.isRotate = true
        }

        this.rotateTo = (step) => {
            q1.rotateTowards(q2, step)
            editorCamera.position.set(0, 0, 1).applyQuaternion(q1).multiplyScalar(radius).add(focusPoint)

            editorCamera.quaternion.rotateTowards(targetQuaternion, step)

            if (q1.angleTo(q2) === 0) {
                this.isRotate = false
                if (this.onComplete) this.onComplete()
            }
        }
    }
}



/**
 * 控制相机看向指定坐标
 */
export class RotationCamera {
    constructor(cameraToBeControl) {

        this.camera = cameraToBeControl
        this.rotationMatrix = new Matrix4()
        this.targetQuaternion = new Quaternion()
        this.speed = .02
        this.isRunning = false
        this.onComplete = null

        this.update = () => {

            if (!this.camera.quaternion.equals(this.targetQuaternion)) {

                this.isRunning = true
                this.camera.quaternion.rotateTowards(this.targetQuaternion, this.speed)
                requestAnimationFrame(this.update)

            } else {

                this._onComplete()

            }

        }

        this.setWorldPosition = (worldPosition, run = true) => {

            this.rotationMatrix.lookAt(worldPosition.clone().negate(), this.camera.position, this.camera.up)
            this.targetQuaternion.setFromRotationMatrix(this.rotationMatrix)
            if (run && !this.isRunning) this.update()
            return this.targetQuaternion

        }

        this._onComplete = () => {

            this.isRunning = false
            if (this.onComplete) this.onComplete()
        }
    }
}
